/*****************************************************************************
* @author  : windsPx                                                             *
* @date    :                                                                 *
* @file    :                                                                 *
* @brief   :                                                                 *
*----------------------------------------------------------------------------*
* Date        | Version   | Author         | Description                     *
*---------------------------------------------------------------------------- *
*             |           |  windsPx              |          
*****************************************************************************/

#pragma once

#include "CommonDef.h"

/*
* 单进程内同类型对象的递增ID
*/
#if (0)
#define BUF_TRANS
#endif
namespace _disruptor
{
/*
* 单进程内同类型对象的递增ID
*/
template <typename T = void>
class CAtomID
{
public:
	int64_t m_id;
	//! 递增的id
	static std::atomic<int64_t> m_inc_id;
public:
	CAtomID()
	{
        m_id = m_inc_id.fetch_add(1);
		printf("_id = %lld \n", m_id);
	}
	~CAtomID() {}
};
template <typename T> std::atomic<int64_t> CAtomID<T>::m_inc_id = { 0 };

/*
 * 生产/消费 参与者基类
*/
//生产代理基类
class CProduceProxyBase
{
public:
	virtual void initProducer(int producer_id) = 0;
	virtual void writeData(int producer_id, const char* pdata, int length) = 0;
	virtual void writeData(int producer_id, void* obj) = 0;
#ifdef BUF_TRANS
    virtual char* writeData(int producer_id) = 0;
    virtual void commit() = 0;
#endif
};

class CCustomFace
{
public:
	virtual int getMemType() = 0;
	virtual void initCustomer(int custom_id) = 0;
};

template <typename C>
class CBaseParticipant : public CAtomID<C>
{
public:
	CBaseParticipant(CCustomFace* proxy) : m_custom_proxy(proxy)
	{
		m_custom_proxy->initCustomer(GetId());
	}
	CBaseParticipant(CProduceProxyBase* proxy) : m_produce_proxy(proxy)
	{
		m_produce_proxy->initProducer(GetId());
	}
	~CBaseParticipant() {}
protected:
	CProduceProxyBase* m_produce_proxy = NULL;
	CCustomFace* m_custom_proxy = NULL;
	//! 当前访问ring的序号
    char pad[56];
	std::atomic<RINGINDEX> m_order_num = 0;
    char pad1[64];
public:
	int GetId() { return CAtomID<C>::m_id; }
	void setCurOrderNum(RINGINDEX order_num) { m_order_num = order_num; }
	RINGINDEX GetCurOrderNum() { return m_order_num; }
};

/*
 * 生产者基类
 */
template <typename CONCRETE_PRODUCER>
class CBaseProducer : public CBaseParticipant<CONCRETE_PRODUCER>
{
protected:
	class CProduceProxyBase* m_ref_proxy;
public:
	CBaseProducer(CProduceProxyBase* ref_proxy)
		: m_ref_proxy(ref_proxy), CBaseParticipant<CONCRETE_PRODUCER>(ref_proxy)
	{
	}
	virtual ~CBaseProducer() {}
public:
	void produceData(const char* pdata, int length)
	{
		m_ref_proxy->writeData(CBaseParticipant<CONCRETE_PRODUCER>::GetId(), pdata, length);
	}
#ifdef BUF_TRANS
    char* produceData()
    {
        return m_ref_proxy->writeData(CBaseParticipant<CONCRETE_PRODUCER>::GetId());
    }
    void commit()
    {
        m_ref_proxy->commit();
    }
#endif
	//操作对象示例
	template<typename T>
	void produceData(std::shared_ptr<T>& pdata)
	{
		m_ref_proxy->writeData(CBaseParticipant<CONCRETE_PRODUCER>::GetId(), (void*)&pdata);
	}
};

/*
 * ring中元素对象的基类
 */
class CRingEntry
{
public:
	//直接写数据
	virtual void WriteData(const char* data, int length) {};
	//缓存对象指针
	virtual void SetInnerObj(void* obj, int num) {};
#ifdef BUF_TRANS
    virtual char* bufPos() { return NULL; }
#endif
};

//数据缓存的基础对象
template <int BufLen = BuffSize>
class CEntryBuffer : public CRingEntry
{
public:
	int m_used = 0;
	unsigned char m_data[BufLen] = {0};
public:
	//业务上自定义类型的结构 必须为框架提供这个接口实现
	void WriteData(const char* data, int length) override
	{
		assert(length < BuffSize);
		m_used = length;
		memcpy(m_data, data, length);
		m_data[length] = 0;
	}

#ifdef BUF_TRANS
    virtual char* bufPos() override
    {
        return (char*)m_data;
    }
#endif
};

//缓存被处理对象指针的基础结构 -- 由外部业务层释放inner_ptr
template <typename T>
class CEntryBufObj : public CRingEntry
{
public:
	using OBJType = T;
    CEntryBufObj() : m_inner_ptr(NULL), m_ref_count(0)
	{
	}
	CEntryBufObj(const CEntryBufObj& obj)
        : m_inner_ptr(obj.m_inner_ptr), m_ref_count(obj.m_ref_count.load())
	{
	}
private:
	std::shared_ptr<OBJType> m_inner_ptr = nullptr;
    std::atomic<int> m_ref_count;
public:
/*
    void SetInnerObj(void* obj, int num) override
    {
        m_ref_count.store(num, std::memory_order_acq_rel);
        m_inner_ptr = *((std::shared_ptr<OBJType>*)(obj));
    }
    std::shared_ptr<OBJType> GetInnerPtr()
    {
        std::shared_ptr<OBJType> obj(m_inner_ptr);
        m_ref_count.fetch_sub(1, std::memory_order_release);
        if (m_ref_count.load(std::memory_order_relaxed) == 0)
            m_inner_ptr.reset();
        return obj;
    }
*/
    void SetInnerObj(void* obj, int num) override
    {
        if (m_ref_count.load(std::memory_order_acquire) == 0)
            m_inner_ptr.reset();
        m_ref_count.store(num, std::memory_order_acq_rel);
        m_inner_ptr = *((std::shared_ptr<OBJType>*)(obj));
    }
    std::shared_ptr<OBJType> GetInnerPtr()
    {
        std::shared_ptr<OBJType> obj(m_inner_ptr);
        m_ref_count.fetch_sub(1, std::memory_order_release);
        return obj;
    }
};

//求类型们的最大sizeof
template <typename... T>
struct MaxTypeSize;

template <typename T>
struct MaxTypeSize<T>
{
    enum { value = sizeof(T) };
};

template <typename T1, typename T2>
struct MaxTypeSize<T1, T2>
{
    enum { value = MaxTypeSize<T1>::value > MaxTypeSize<T2>::value ? MaxTypeSize<T1>::value : MaxTypeSize<T2>::value };
};

template <typename T1, typename... T2>
struct MaxTypeSize<T1, T2...>
{
    enum { value = MaxTypeSize<T1>::value > MaxTypeSize<T2...>::value ? MaxTypeSize<T1>::value : MaxTypeSize<T2...>::value };
};

}
